﻿#include "NddExport.h"
#include <qsciscintilla.h>
#include "Scintilla.h"

#include <QMessageBox> /*dubug */
#include <QFile>
#include <QTextStream>
#include <QtXml/QDomDocument>
#include <QTextStream>
#include <QFileDialog>
#include <QPrinter>
#include <QTextDocument>
#include <QMenuBar>

#include <QApplication>
#include <QClipboard>
#include <QMimeData>
#include <QObject>

#pragma execution_character_set("utf-8")

extern std::function<QsciScintilla* (QWidget*)> s_getCurEdit;

ExporterClass::ExporterClass(QObject* parent, QWidget* pNotepad)
{
    m_pNotepad = pNotepad;
    csd.dataBuffer = nullptr;
    csd.styles = nullptr;
}


ExporterClass::~ExporterClass()
{
    if (nullptr != csd.styles)
    {
        delete[] csd.styles;
    }
    if (nullptr != csd.dataBuffer)
    {
        delete[] csd.dataBuffer;
    }
}

void ExporterClass::doExportPDF()
{
    QsciScintilla* pEdit = s_getCurEdit(m_pNotepad);
    if (pEdit == nullptr)
    {
        return;
    }

    fillScintillaData(pEdit);

    const int buflen = pEdit->length() + 1;

    char* buffer = csd.dataBuffer;

    size_t totalBytesNeeded = 1;	//zero terminator

    totalBytesNeeded += EXPORT_SIZE_HTML_STATIC + EXPORT_SIZE_HTML_STYLE * (csd.nrUsedStyles - 1) + csd.totalFontStringLength + EXPORT_SIZE_HTML_SWITCH * csd.nrStyleSwitches;
    int startHTML = 105, endHTML = 0, startFragment = 0, endFragment = 0;

    unsigned char testChar = 0;
    for (int i = 0; i < buflen; i++) {
        testChar = buffer[(i * 2)];
        switch (testChar) {
        case '\r':
            if (buffer[(i * 2) + 2] == '\n')
                break;
        case '\n':
            totalBytesNeeded += 2;	//	plain newline
            break;
        case '<':
            totalBytesNeeded += 4;	// '&lt;'
            break;
        case '>':
            totalBytesNeeded += 4;	// '&gt;'
            break;
        case '&':
            totalBytesNeeded += 5;	// '&amp;'
            break;
        case '\t':
            totalBytesNeeded += 4;
            break;
        default:
            if (testChar < 0x20)	//	ignore control characters
                break;
            totalBytesNeeded += 1; //	'char'
            break;
        }
    }
    char* clipbuffer = new char[totalBytesNeeded];
    int currentBufferOffset = 0;
    if (clipbuffer == nullptr)
    {
        return;
    }

    clipbuffer[0] = 0;

    //begin building context
    //proper doctype to pass validation, just because it looks good
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset,
        "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd\">"
        "\r\n");
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<html>\r\n");

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<head>\r\n");

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<META http-equiv=Content-Type content=\"text/html; charset=");
    if (1) {
        currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "UTF-8");
    }
    else {
        currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "iso-8859-1");
    }
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\">\r\n");
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<title>Exported from Notepad--</title>\r\n");

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<style type=\"text/css\">\r\n");

    StyleData* currentStyle, * defaultStyle;
    defaultStyle = (csd.styles) + STYLE_DEFAULT;

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "span {\r\n");
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-family: '%s';\r\n", defaultStyle->fontString);
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-size: %0dpt;\r\n", defaultStyle->size);
    if (defaultStyle->bold)		currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-weight: bold;\r\n");
    if (defaultStyle->italic)	currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-style: italic;\r\n");
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tcolor: #%02X%02X%02X;\r\n", (defaultStyle->fgColor >> 0) & 0xFF, (defaultStyle->fgColor >> 8) & 0xFF, (defaultStyle->fgColor >> 16) & 0xFF);
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "}\r\n");

    for (int i = 0; i < NRSTYLES; i++) {
        if (i == STYLE_DEFAULT)
            continue;

        currentStyle = (csd.styles) + i;
        if (csd.usedStyles[i] == true) {
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, ".sc%d {\r\n", i);
            if (QString::compare(currentStyle->fontString, defaultStyle->fontString, Qt::CaseInsensitive))	//this is forcefully set to ANSI, this part of the plugin does not need Unicode
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-family: '%s';\r\n", currentStyle->fontString);
            if (currentStyle->size != defaultStyle->size)
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-size: %0dpt;\r\n", currentStyle->size);
            if (currentStyle->bold != defaultStyle->bold) {
                if (currentStyle->bold)
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-weight: bold;\r\n");
                else
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-weight: normal;\r\n");
            }
            if (currentStyle->italic != defaultStyle->italic) {
                if (currentStyle->italic)
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-style: italic;\r\n");
                else
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-style: normal;\r\n");
            }
            if (currentStyle->underlined)
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\ttext-decoration: underline;\r\n");
            if (currentStyle->fgColor != defaultStyle->fgColor)
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tcolor: #%02X%02X%02X;\r\n", (currentStyle->fgColor >> 0) & 0xFF, (currentStyle->fgColor >> 8) & 0xFF, (currentStyle->fgColor >> 16) & 0xFF);
            if (currentStyle->bgColor != defaultStyle->bgColor)
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tbackground: #%02X%02X%02X;\r\n", (currentStyle->bgColor >> 0) & 0xFF, (currentStyle->bgColor >> 8) & 0xFF, (currentStyle->bgColor >> 16) & 0xFF);
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "}\r\n");
        }
    }

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "</style>\r\n</head>\r\n");
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<body>\r\n");

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<div style=\"");

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset,
        "float: left; "
        "white-space: pre; "
        "line-height: 1; "
        "background: #%02X%02X%02X; ",
        (defaultStyle->bgColor >> 0) & 0xFF, (defaultStyle->bgColor >> 8) & 0xFF, (defaultStyle->bgColor >> 16) & 0xFF
    );

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\">");

    char* tabBuffer = new char[static_cast<size_t>(4 + 1)];
    tabBuffer[0] = 0;
    for (int i = 0; i < 4; i++) {
        strcat(tabBuffer, " ");
    }

    int nrCharsSinceLinebreak = -1, nrTabCharsToSkip = 0;
    int lastStyle = -1;
    unsigned char currentChar;
    bool openSpan = false;

    for (int i = 0; i < buflen; i++) {
        //print new span object if style changes
        if (buffer[i * 2 + 1] != lastStyle) {
            if (openSpan) {
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "</span>");
            }
            lastStyle = buffer[i * 2 + 1];
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<span class=\"sc%d\">", lastStyle);
            openSpan = true;
        }

        //print character, parse special ones
        currentChar = buffer[i * 2];
        nrCharsSinceLinebreak++;
        switch (currentChar) {
        case '\r':
            if (buffer[(i * 2) + 2] == '\n')
                break;
        case '\n':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\r\n");
            nrCharsSinceLinebreak = -1;
            break;
        case '<':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "&lt;");
            break;
        case '>':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "&gt;");
            break;
        case '&':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "&amp;");
            break;
        case '\t':
            nrTabCharsToSkip = nrCharsSinceLinebreak % (4);
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "%s", tabBuffer + (nrTabCharsToSkip));
            nrCharsSinceLinebreak += 4 - nrTabCharsToSkip - 1;
            break;
        default:
            if (currentChar < 0x20)	//ignore control characters
                break;
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "%c", currentChar);
            break;
        }
    }

    if (openSpan) {
        currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "</span>");
    }

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "</div>");

    delete[] tabBuffer;

    //add closing context
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "</body>\r\n</html>\r\n");
    endHTML = currentBufferOffset;

    QString fileName = QFileDialog::getSaveFileName(NULL, tr("Save File"), QString(), tr("PDFFiles (*.pdf);"));
    if (fileName.isEmpty())
        return;
    if (!fileName.endsWith(QLatin1String(".pdf")))
        fileName += QLatin1String(".pdf");

    QPrinter printer;
    printer.setOutputFormat(QPrinter::PdfFormat);
    printer.setOutputFileName(fileName);
    QTextDocument document;

    document.setHtml(clipbuffer);

    document.print(&printer);

    delete[] clipbuffer;
}

void ExporterClass::doExportRTF()
{
    QsciScintilla* pEdit = s_getCurEdit(m_pNotepad);
    if (pEdit == nullptr)
    {
        return;
    }

    fillScintillaData(pEdit);

    char* buffer = csd.dataBuffer;
    bool isUnicode = (csd.currentCodePage == SC_CP_UTF8);

    size_t totalBytesNeeded = 1;	//zero terminator

    totalBytesNeeded += EXPORT_SIZE_RTF_STATIC + EXPORT_SIZE_RTF_STYLE * csd.nrUsedStyles + csd.totalFontStringLength + EXPORT_SIZE_RTF_SWITCH * csd.nrStyleSwitches;

    unsigned char testChar = 0;
    for (int i = 0; i < csd.nrChars; i++) {
        testChar = buffer[(i * 2)];
        switch (testChar) {
        case '{':
            totalBytesNeeded += 2;	// '\{'
            break;
        case '}':
            totalBytesNeeded += 2;	// '\}'
            break;
        case '\\':
            totalBytesNeeded += 2;	// '\\'
            break;
        case '\t':
            totalBytesNeeded += 5;	// '\tab '
            break;
        case '\r':
            if (buffer[(i + 1) * 2] == '\n')
                break;
        case '\n':
            totalBytesNeeded += 6;	// '\par\r\n'
            break;
        default:
            if (testChar < 0x80 || !isUnicode)
                totalBytesNeeded += 1;	// 'char'
            else {
                totalBytesNeeded += 8;	// '\u#####?
                i++;
                if (testChar >= 0xE0)
                    i++;
            }

            break;
        }
    }

    int currentBufferOffset = 0;

    char* clipbuffer = new char[totalBytesNeeded];

    clipbuffer[0] = 0;

    int txSize = csd.tabSize * csd.twipsPerSpace;

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "{\\rtf1\\ansi\\deff0\\deftab%u\r\n\r\n", static_cast<unsigned>(txSize));
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "{\\fonttbl\r\n");

    StyleData* currentStyle;

    int currentFontIndex = 0;
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "{\\f%03d %s;}\r\n", currentFontIndex, (csd.styles + STYLE_DEFAULT)->fontString);
    currentFontIndex++;

    for (int i = 0; i < NRSTYLES; i++) {
        if (i == STYLE_DEFAULT)
            continue;
        if (csd.usedStyles[i] == true) {
            currentStyle = (csd.styles) + i;
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "{\\f%03d %s;}\r\n", currentFontIndex, currentStyle->fontString);
            if (!strcmp(currentStyle->fontString, (csd.styles + STYLE_DEFAULT)->fontString)) {
                currentStyle->fontIndex = (csd.styles + STYLE_DEFAULT)->fontIndex;
            }
            else {
                currentStyle->fontIndex = currentFontIndex;
            }
            currentFontIndex++;
        }
    }


    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "}\r\n\r\n");	//fonttbl
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "{\\colortbl\r\n");

    int currentColorIndex = 0;
    for (int i = 0; i < NRSTYLES; i++) {
        if (csd.usedStyles[i] == true) {
            currentStyle = (csd.styles) + i;

            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\red%03d\\green%03d\\blue%03d;\r\n", (currentStyle->fgColor >> 0) & 0xFF, (currentStyle->fgColor >> 8) & 0xFF, (currentStyle->fgColor >> 16) & 0xFF);
            currentStyle->fgClrIndex = currentColorIndex;
            currentColorIndex++;

            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\red%03d\\green%03d\\blue%03d;\r\n", (currentStyle->bgColor >> 0) & 0xFF, (currentStyle->bgColor >> 8) & 0xFF, (currentStyle->bgColor >> 16) & 0xFF);
            currentStyle->bgClrIndex = currentColorIndex;
            currentColorIndex++;
        }
    }

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "}\r\n\r\n");	//colortbl

    //-------Dump text to RTF
    int lastStyle = -1;
    int prevStyle = STYLE_DEFAULT;
    int bufferStyle = STYLE_DEFAULT;
    unsigned char currentChar;
    StyleData* styles = csd.styles;
    utf16 unicodeValue{};

    //print default style information
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\f%d\\fs%d\\cb%d\\cf%d ", styles[STYLE_DEFAULT].fontIndex, styles[STYLE_DEFAULT].size * 2, styles[STYLE_DEFAULT].bgClrIndex, styles[STYLE_DEFAULT].fgClrIndex);

    for (int i = 0; i < csd.nrChars; i++) {
        currentChar = buffer[(i * 2)];
        bufferStyle = buffer[(i * 2) + 1];

        //print new style info if style changes
        if (lastStyle != bufferStyle) {
            if (lastStyle != -1)
                prevStyle = lastStyle;
            lastStyle = bufferStyle;
            //currentBufferOffset += sprintf(clipbuffer+currentBufferOffset, "\\f%d\\fs%d\\cb%d\\cf%d", styles[lastStyle].fontIndex, styles[lastStyle].size * 2, styles[lastStyle].bgClrIndex, styles[lastStyle].fgClrIndex);

            if (styles[lastStyle].fontIndex != styles[prevStyle].fontIndex) {
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\f%d", styles[lastStyle].fontIndex);
            }
            if (styles[lastStyle].size != styles[prevStyle].size) {
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\fs%d", styles[lastStyle].size * 2);
            }
            if (styles[lastStyle].bgClrIndex != styles[prevStyle].bgClrIndex) {
                //currentBufferOffset += sprintf(clipbuffer+currentBufferOffset, "\\cb%d", styles[lastStyle].bgClrIndex);
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\highlight%d", styles[lastStyle].bgClrIndex);
            }
            if (styles[lastStyle].fgClrIndex != styles[prevStyle].fgClrIndex) {
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\cf%d", styles[lastStyle].fgClrIndex);
            }
            ///////////////////////
            if (styles[lastStyle].bold != styles[prevStyle].bold) {
                if (styles[lastStyle].bold) {
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\b");
                }
                else {
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\b0");
                }
            }
            if (styles[lastStyle].italic != styles[prevStyle].italic) {
                if (styles[lastStyle].underlined) {
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\i");
                }
                else {
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\i0");
                }
            }
            if (styles[lastStyle].underlined != styles[prevStyle].underlined) {
                if (styles[lastStyle].underlined) {
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\ul");
                }
                else {
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\ul0");
                }
            }
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, " ");
        }

        //print character, parse special ones
        switch (currentChar) {
        case '{':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\{");
            break;
        case '}':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\}");
            break;
        case '\\':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\\\");
            break;
        case '\t':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\tab ");
            break;
        case '\r':
            if (buffer[(i * 2) + 2] == '\n')
                break;
        case '\n':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\par\r\n");
            break;
        default:
            if (currentChar < 0x20)	//ignore control characters
                break;
            if (currentChar > 0x7F && isUnicode) {	//this may be some UTF-8 character, so parse it as such
                unicodeValue.value = 0;

                if (currentChar < 0xE0) {
                    unicodeValue.value = ((0x1F & currentChar) << 6);
                    i++; currentChar = buffer[(i * 2)];
                    unicodeValue.value |= (0x3F & currentChar);
                }
                else {
                    unicodeValue.value = ((0xF & currentChar) << 12);
                    i++; currentChar = buffer[(i * 2)];
                    unicodeValue.value |= ((0x3F & currentChar) << 6);
                    i++; currentChar = buffer[(i * 2)];
                    unicodeValue.value |= (0x3F & currentChar);
                }

                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\u%d?", unicodeValue.value);	//signed values
            }
            else {
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "%c", currentChar);
            }
            break;
        }
    }

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "}\r\n");	//rtf/ansi
    QString fileName = QFileDialog::getSaveFileName(NULL, tr("Save File"), QString(), tr("RTF Files (*.rtf);"));
    if (fileName.isEmpty())
        return;
    if (!fileName.endsWith(QLatin1String(".rtf")))
        fileName += QLatin1String(".rtf");

    QFile report(fileName);
    report.open(QIODevice::WriteOnly | QIODevice::Truncate);
    report.write(clipbuffer);
    report.close();
    delete[] clipbuffer;
}


void ExporterClass::doExportHTML()
{
    QsciScintilla* pEdit = s_getCurEdit(m_pNotepad);
    if (pEdit == nullptr)
    {
        return;
    }

    fillScintillaData(pEdit);

    const int buflen = pEdit->length() + 1;

    char* buffer = csd.dataBuffer;

    size_t totalBytesNeeded = 1;	//zero terminator

    totalBytesNeeded += EXPORT_SIZE_HTML_STATIC + EXPORT_SIZE_HTML_STYLE * (csd.nrUsedStyles - 1) + csd.totalFontStringLength + EXPORT_SIZE_HTML_SWITCH * csd.nrStyleSwitches;
    int startHTML = 105, endHTML = 0, startFragment = 0, endFragment = 0;

    unsigned char testChar = 0;
    for (int i = 0; i < csd.nrChars ; i++) {
        testChar = buffer[(i * 2)];
        switch (testChar) {
        case '\r':
            if (buffer[(i * 2) + 2] == '\n')
                break;
        case '\n':
            totalBytesNeeded += 2;	//	plain newline
            break;
        case '<':
            totalBytesNeeded += 4;	// '&lt;'
            break;
        case '>':
            totalBytesNeeded += 4;	// '&gt;'
            break;
        case '&':
            totalBytesNeeded += 5;	// '&amp;'
            break;
        case '\t':
            totalBytesNeeded +=4;
            break;
        default:
            if (testChar < 0x20)	//	ignore control characters
                break;
            totalBytesNeeded += 1; //	'char'
            break;
        }
    }
    char* clipbuffer = new char[totalBytesNeeded];
    int currentBufferOffset = 0;

    if (clipbuffer == nullptr)
    {
        return ;
    }

    clipbuffer[0] = 0;

    //begin building context
    //proper doctype to pass validation, just because it looks good
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset,
        "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd\">"
        "\r\n");
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<html>\r\n");

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<head>\r\n");

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<META http-equiv=Content-Type content=\"text/html; charset=");
    if (csd.currentCodePage == SC_CP_UTF8) {
        currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "UTF-8");
    }
    else if (csd.currentCodePage == SC_CHARSET_GB2312)
    {
        currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "GB2312");
    }
    else {
        currentBufferOffset += sprintf(clipbuffer+currentBufferOffset, "iso-8859-1");
    }
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\">\r\n");
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<title>Exported from Notepad--</title>\r\n");

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<style type=\"text/css\">\r\n");

    StyleData* currentStyle, * defaultStyle;
    defaultStyle = (csd.styles) + STYLE_DEFAULT;

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "span {\r\n");
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-family: '%s';\r\n", defaultStyle->fontString);
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-size: %0dpt;\r\n", defaultStyle->size);
    if (defaultStyle->bold)		currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-weight: bold;\r\n");
    if (defaultStyle->italic)	currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-style: italic;\r\n");
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tcolor: #%02X%02X%02X;\r\n", (defaultStyle->fgColor >> 0) & 0xFF, (defaultStyle->fgColor >> 8) & 0xFF, (defaultStyle->fgColor >> 16) & 0xFF);
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "}\r\n");

    for (int i = 0; i < NRSTYLES; i++) {
        if (i == STYLE_DEFAULT)
            continue;

        currentStyle = (csd.styles) + i;
        if (csd.usedStyles[i] == true) {
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, ".sc%d {\r\n", i);
            if (QString::compare(currentStyle->fontString, defaultStyle->fontString), Qt::CaseInsensitive)	//this is forcefully set to ANSI, this part of the plugin does not need Unicode
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-family: '%s';\r\n", currentStyle->fontString);
            if (currentStyle->size != defaultStyle->size)
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-size: %0dpt;\r\n", currentStyle->size);
            if (currentStyle->bold != defaultStyle->bold) {
                if (currentStyle->bold)
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-weight: bold;\r\n");
                else
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-weight: normal;\r\n");
            }
            if (currentStyle->italic != defaultStyle->italic) {
                if (currentStyle->italic)
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-style: italic;\r\n");
                else
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-style: normal;\r\n");
            }
            if (currentStyle->underlined)
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\ttext-decoration: underline;\r\n");
            if (currentStyle->fgColor != defaultStyle->fgColor)
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tcolor: #%02X%02X%02X;\r\n", (currentStyle->fgColor >> 0) & 0xFF, (currentStyle->fgColor >> 8) & 0xFF, (currentStyle->fgColor >> 16) & 0xFF);
            if (currentStyle->bgColor != defaultStyle->bgColor)
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tbackground: #%02X%02X%02X;\r\n", (currentStyle->bgColor >> 0) & 0xFF, (currentStyle->bgColor >> 8) & 0xFF, (currentStyle->bgColor >> 16) & 0xFF);
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "}\r\n");
        }
    }

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "</style>\r\n</head>\r\n");
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<body>\r\n");

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<div style=\"");

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset,
        "float: left; "
        "white-space: pre; "
        "line-height: 1; "
        "background: #%02X%02X%02X; ",
        (defaultStyle->bgColor >> 0) & 0xFF, (defaultStyle->bgColor >> 8) & 0xFF, (defaultStyle->bgColor >> 16) & 0xFF
    );

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\">");

    char* tabBuffer = new char[static_cast<size_t>(4 + 1)];
    tabBuffer[0] = 0;
    for (int i = 0; i <4; i++) {
        strcat(tabBuffer, " ");
    }

    int nrCharsSinceLinebreak = -1, nrTabCharsToSkip = 0;
    int lastStyle = -1;
    unsigned char currentChar;
    bool openSpan = false;

    for (int i = 0; i < csd.nrChars; i++) {
        //print new span object if style changes
        if (buffer[i * 2 + 1] != lastStyle) {
            if (openSpan) {
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "</span>");
            }
            lastStyle = buffer[i * 2 + 1];
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<span class=\"sc%d\">", lastStyle);
            openSpan = true;
        }

        //print character, parse special ones
        currentChar = buffer[i*2];
        nrCharsSinceLinebreak++;
        switch (currentChar) {
        case '\r':
            if (buffer[(i * 2) + 2] == '\n')
                break;
        case '\n':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\r\n");
            nrCharsSinceLinebreak = -1;
            break;
        case '<':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "&lt;");
            break;
        case '>':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "&gt;");
            break;
        case '&':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "&amp;");
            break;
        case '\t':
            nrTabCharsToSkip = nrCharsSinceLinebreak % (4);
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "%s", tabBuffer + (nrTabCharsToSkip));
            nrCharsSinceLinebreak += 4 - nrTabCharsToSkip - 1;
            break;
        default:
            if (currentChar < 0x20)	//ignore control characters
                break;
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "%c", currentChar);
            break;
        }
    }

    if (openSpan) {
        currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "</span>");
    }

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "</div>");

    delete[] tabBuffer;

    //add closing context
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "</body>\r\n</html>\r\n");
    endHTML = currentBufferOffset;

    QString fileName = QFileDialog::getSaveFileName(NULL, tr("Save File"), QString(), tr("HTML Files (*.html);"));
    if (fileName.isEmpty())
        return;
    if (!fileName.endsWith(QLatin1String(".html")))
        fileName += QLatin1String(".html");

    QFile report(fileName);
    report.open(QIODevice::WriteOnly | QIODevice::Truncate);
    report.write(clipbuffer);
    report.close();
    delete[] clipbuffer;

}

void ExporterClass::copyExportRTFclipboard()
{
    QsciScintilla* pEdit = s_getCurEdit(m_pNotepad);
    if (pEdit == nullptr)
    {
        return;
    }

    fillScintillaData(pEdit);

    const int buflenAll = pEdit->length() + 1;

    char* textbuf = new char[buflenAll];

    if (pEdit->hasSelectedText())
    {
        pEdit->SendScintilla(SCI_GETSELTEXT,textbuf);
    }
    else
    {
        pEdit->SendScintilla(SCI_GETTEXT, buflenAll, textbuf);
    }


    char* buffer = csd.dataBuffer;
    bool isUnicode = (csd.currentCodePage == SC_CP_UTF8);

    size_t totalBytesNeeded = 1;	//zero terminator

    totalBytesNeeded += EXPORT_SIZE_RTF_STATIC + EXPORT_SIZE_RTF_STYLE * csd.nrUsedStyles + csd.totalFontStringLength + EXPORT_SIZE_RTF_SWITCH * csd.nrStyleSwitches;

    unsigned char testChar = 0;
    for (int i = 0; i < csd.nrChars; i++) {
        testChar = buffer[(i * 2)];
        switch (testChar) {
        case '{':
            totalBytesNeeded += 2;	// '\{'
            break;
        case '}':
            totalBytesNeeded += 2;	// '\}'
            break;
        case '\\':
            totalBytesNeeded += 2;	// '\\'
            break;
        case '\t':
            totalBytesNeeded += 5;	// '\tab '
            break;
        case '\r':
            if (buffer[(i + 1) * 2] == '\n')
                break;
        case '\n':
            totalBytesNeeded += 6;	// '\par\r\n'
            break;
        default:
            if (testChar < 0x80 || !isUnicode)
                totalBytesNeeded += 1;	// 'char'
            else {
                totalBytesNeeded += 8;	// '\u#####?
                i++;
                if (testChar >= 0xE0)
                    i++;
            }

            break;
        }
    }

    int currentBufferOffset = 0;

    char* clipbuffer = new char[totalBytesNeeded];

    clipbuffer[0] = 0;

    int txSize = csd.tabSize * csd.twipsPerSpace;

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "{\\rtf1\\ansi\\deff0\\deftab%u\r\n\r\n", static_cast<unsigned>(txSize));
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "{\\fonttbl\r\n");

    StyleData* currentStyle;

    int currentFontIndex = 0;
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "{\\f%03d %s;}\r\n", currentFontIndex, (csd.styles + STYLE_DEFAULT)->fontString);
    currentFontIndex++;

    for (int i = 0; i < NRSTYLES; i++) {
        if (i == STYLE_DEFAULT)
            continue;
        if (csd.usedStyles[i] == true) {
            currentStyle = (csd.styles) + i;
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "{\\f%03d %s;}\r\n", currentFontIndex, currentStyle->fontString);
            if (!strcmp(currentStyle->fontString, (csd.styles + STYLE_DEFAULT)->fontString)) {
                currentStyle->fontIndex = (csd.styles + STYLE_DEFAULT)->fontIndex;
            }
            else {
                currentStyle->fontIndex = currentFontIndex;
            }
            currentFontIndex++;
        }
    }


    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "}\r\n\r\n");	//fonttbl
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "{\\colortbl\r\n");

    int currentColorIndex = 0;
    for (int i = 0; i < NRSTYLES; i++) {
        if (csd.usedStyles[i] == true) {
            currentStyle = (csd.styles) + i;

            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\red%03d\\green%03d\\blue%03d;\r\n", (currentStyle->fgColor >> 0) & 0xFF, (currentStyle->fgColor >> 8) & 0xFF, (currentStyle->fgColor >> 16) & 0xFF);
            currentStyle->fgClrIndex = currentColorIndex;
            currentColorIndex++;

            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\red%03d\\green%03d\\blue%03d;\r\n", (currentStyle->bgColor >> 0) & 0xFF, (currentStyle->bgColor >> 8) & 0xFF, (currentStyle->bgColor >> 16) & 0xFF);
            currentStyle->bgClrIndex = currentColorIndex;
            currentColorIndex++;
        }
    }

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "}\r\n\r\n");	//colortbl

    //-------Dump text to RTF
    int lastStyle = -1;
    int prevStyle = STYLE_DEFAULT;
    int bufferStyle = STYLE_DEFAULT;
    unsigned char currentChar;
    StyleData* styles = csd.styles;
    utf16 unicodeValue{};

    //print default style information
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\f%d\\fs%d\\cb%d\\cf%d ", styles[STYLE_DEFAULT].fontIndex, styles[STYLE_DEFAULT].size * 2, styles[STYLE_DEFAULT].bgClrIndex, styles[STYLE_DEFAULT].fgClrIndex);

    for (int i = 0; i < csd.nrChars; i++) {
        currentChar = buffer[(i * 2)];
        bufferStyle = buffer[(i * 2) + 1];

        //print new style info if style changes
        if (lastStyle != bufferStyle) {
            if (lastStyle != -1)
                prevStyle = lastStyle;
            lastStyle = bufferStyle;
            //currentBufferOffset += sprintf(clipbuffer+currentBufferOffset, "\\f%d\\fs%d\\cb%d\\cf%d", styles[lastStyle].fontIndex, styles[lastStyle].size * 2, styles[lastStyle].bgClrIndex, styles[lastStyle].fgClrIndex);

            if (styles[lastStyle].fontIndex != styles[prevStyle].fontIndex) {
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\f%d", styles[lastStyle].fontIndex);
            }
            if (styles[lastStyle].size != styles[prevStyle].size) {
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\fs%d", styles[lastStyle].size * 2);
            }
            if (styles[lastStyle].bgClrIndex != styles[prevStyle].bgClrIndex) {
                //currentBufferOffset += sprintf(clipbuffer+currentBufferOffset, "\\cb%d", styles[lastStyle].bgClrIndex);
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\highlight%d", styles[lastStyle].bgClrIndex);
            }
            if (styles[lastStyle].fgClrIndex != styles[prevStyle].fgClrIndex) {
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\cf%d", styles[lastStyle].fgClrIndex);
            }
            ///////////////////////
            if (styles[lastStyle].bold != styles[prevStyle].bold) {
                if (styles[lastStyle].bold) {
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\b");
                }
                else {
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\b0");
                }
            }
            if (styles[lastStyle].italic != styles[prevStyle].italic) {
                if (styles[lastStyle].underlined) {
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\i");
                }
                else {
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\i0");
                }
            }
            if (styles[lastStyle].underlined != styles[prevStyle].underlined) {
                if (styles[lastStyle].underlined) {
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\ul");
                }
                else {
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\ul0");
                }
            }
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, " ");
        }

        //print character, parse special ones
        switch (currentChar) {
        case '{':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\{");
            break;
        case '}':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\}");
            break;
        case '\\':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\\\");
            break;
        case '\t':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\tab ");
            break;
        case '\r':
            if (buffer[(i * 2) + 2] == '\n')
                break;
        case '\n':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\par\r\n");
            break;
        default:
            if (currentChar < 0x20)	//ignore control characters
                break;
            if (currentChar > 0x7F && isUnicode) {	//this may be some UTF-8 character, so parse it as such
                unicodeValue.value = 0;

                if (currentChar < 0xE0) {
                    unicodeValue.value = ((0x1F & currentChar) << 6);
                    i++; currentChar = buffer[(i * 2)];
                    unicodeValue.value |= (0x3F & currentChar);
                }
                else {
                    unicodeValue.value = ((0xF & currentChar) << 12);
                    i++; currentChar = buffer[(i * 2)];
                    unicodeValue.value |= ((0x3F & currentChar) << 6);
                    i++; currentChar = buffer[(i * 2)];
                    unicodeValue.value |= (0x3F & currentChar);
                }

                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\\u%d?", unicodeValue.value);	//signed values
            }
            else {
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "%c", currentChar);
            }
            break;
        }
    }

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "}\r\n");	//rtf/ansi

    QMimeData* mimeData = new QMimeData();
    QByteArray ba;

    ba.append(clipbuffer);
    mimeData->setData("Rich Text Format", ba);
    QApplication::clipboard()->setMimeData(mimeData);

    delete[] clipbuffer;
    delete[] textbuf;
}

void ExporterClass::copyExportHTMLclipboard()
{
    QsciScintilla* pEdit = s_getCurEdit(m_pNotepad);
    if (pEdit == nullptr)
    {
        return;
    }

    fillScintillaData(pEdit);

    const int buflenALL = pEdit->length() + 1;

    char* textbuf = new char[buflenALL];

    if (pEdit->hasSelectedText())
    {
        pEdit->SendScintilla(SCI_GETSELTEXT, textbuf);
    }
    else
    {

        pEdit->SendScintilla(SCI_GETTEXT, buflenALL, textbuf);
    }
    
    char* buffer = csd.dataBuffer;

    size_t totalBytesNeeded = 1;	//zero terminator

    totalBytesNeeded += EXPORT_SIZE_HTML_STATIC + EXPORT_SIZE_HTML_STYLE * (csd.nrUsedStyles - 1) + csd.totalFontStringLength + EXPORT_SIZE_HTML_SWITCH * csd.nrStyleSwitches;;
    int startHTML = 105, endHTML = 0, startFragment = 0, endFragment = 0;

    unsigned char testChar = 0;
    for (int i = 0; i < csd.nrChars; i++) {
        testChar = buffer[(i * 2)];
        switch (testChar) {
        case '\r':
            if (buffer[(i * 2) + 2] == '\n')
                break;
        case '\n':
            totalBytesNeeded += 2;	//	plain newline
            break;
        case '<':
            totalBytesNeeded += 4;	// '&lt;'
            break;
        case '>':
            totalBytesNeeded += 4;	// '&gt;'
            break;
        case '&':
            totalBytesNeeded += 5;	// '&amp;'
            break;
        case '\t':
            totalBytesNeeded += 4;
            break;
        default:
            if (testChar < 0x20)	//	ignore control characters
                break;
            totalBytesNeeded += 1; //	'char'
            break;
        }
    }
    char* clipbuffer = new char[totalBytesNeeded];
    int currentBufferOffset = 0;

    if (clipbuffer == nullptr)
    {
        return;
    }

    clipbuffer[0] = 0;

    //begin building context
    //proper doctype to pass validation, just because it looks good
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset,
        "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd\">"
        "\r\n");
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<html>\r\n");

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<head>\r\n");

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<META http-equiv=Content-Type content=\"text/html; charset=");
    if (csd.currentCodePage == SC_CP_UTF8) {
        currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "UTF-8");
    }
    else if (csd.currentCodePage == SC_CHARSET_GB2312)
    {
        currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "GB2312");
    }
    else {
        currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "iso-8859-1");
    }
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\">\r\n");
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<title>Exported from Notepad--</title>\r\n");

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<style type=\"text/css\">\r\n");

    StyleData* currentStyle, * defaultStyle;
    defaultStyle = (csd.styles) + STYLE_DEFAULT;

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "span {\r\n");
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-family: '%s';\r\n", defaultStyle->fontString);
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-size: %0dpt;\r\n", defaultStyle->size);
    if (defaultStyle->bold)		currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-weight: bold;\r\n");
    if (defaultStyle->italic)	currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-style: italic;\r\n");
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tcolor: #%02X%02X%02X;\r\n", (defaultStyle->fgColor >> 0) & 0xFF, (defaultStyle->fgColor >> 8) & 0xFF, (defaultStyle->fgColor >> 16) & 0xFF);
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "}\r\n");

    for (int i = 0; i < NRSTYLES; i++) {
        if (i == STYLE_DEFAULT)
            continue;

        currentStyle = (csd.styles) + i;
        if (csd.usedStyles[i] == true) {
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, ".sc%d {\r\n", i);
            if (QString::compare(currentStyle->fontString, defaultStyle->fontString), Qt::CaseInsensitive)	//this is forcefully set to ANSI, this part of the plugin does not need Unicode
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-family: '%s';\r\n", currentStyle->fontString);
            if (currentStyle->size != defaultStyle->size)
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-size: %0dpt;\r\n", currentStyle->size);
            if (currentStyle->bold != defaultStyle->bold) {
                if (currentStyle->bold)
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-weight: bold;\r\n");
                else
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-weight: normal;\r\n");
            }
            if (currentStyle->italic != defaultStyle->italic) {
                if (currentStyle->italic)
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-style: italic;\r\n");
                else
                    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tfont-style: normal;\r\n");
            }
            if (currentStyle->underlined)
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\ttext-decoration: underline;\r\n");
            if (currentStyle->fgColor != defaultStyle->fgColor)
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tcolor: #%02X%02X%02X;\r\n", (currentStyle->fgColor >> 0) & 0xFF, (currentStyle->fgColor >> 8) & 0xFF, (currentStyle->fgColor >> 16) & 0xFF);
            if (currentStyle->bgColor != defaultStyle->bgColor)
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\tbackground: #%02X%02X%02X;\r\n", (currentStyle->bgColor >> 0) & 0xFF, (currentStyle->bgColor >> 8) & 0xFF, (currentStyle->bgColor >> 16) & 0xFF);
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "}\r\n");
        }
    }

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "</style>\r\n</head>\r\n");
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<body>\r\n");

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<div style=\"");

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset,
        "float: left; "
        "white-space: pre; "
        "line-height: 1; "
        "background: #%02X%02X%02X; ",
        (defaultStyle->bgColor >> 0) & 0xFF, (defaultStyle->bgColor >> 8) & 0xFF, (defaultStyle->bgColor >> 16) & 0xFF
    );

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\">");

    char* tabBuffer = new char[static_cast<size_t>(4 + 1)];
    tabBuffer[0] = 0;
    for (int i = 0; i < 4; i++) {
        strcat(tabBuffer, " ");
    }

    int nrCharsSinceLinebreak = -1, nrTabCharsToSkip = 0;
    int lastStyle = -1;
    unsigned char currentChar;
    bool openSpan = false;

    for (int i = 0; i < csd.nrChars; i++) {
        //print new span object if style changes
        if (buffer[i * 2 + 1] != lastStyle) {
            if (openSpan) {
                currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "</span>");
            }
            lastStyle = buffer[i * 2 + 1];
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "<span class=\"sc%d\">", lastStyle);
            openSpan = true;
        }

        //print character, parse special ones
        currentChar = buffer[i * 2];
        nrCharsSinceLinebreak++;
        switch (currentChar) {
        case '\r':
            if (buffer[(i * 2) + 2] == '\n')
                break;
        case '\n':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "\r\n");
            nrCharsSinceLinebreak = -1;
            break;
        case '<':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "&lt;");
            break;
        case '>':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "&gt;");
            break;
        case '&':
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "&amp;");
            break;
        case '\t':
            nrTabCharsToSkip = nrCharsSinceLinebreak % (4);
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "%s", tabBuffer + (nrTabCharsToSkip));
            nrCharsSinceLinebreak += 4 - nrTabCharsToSkip - 1;
            break;
        default:
            if (currentChar < 0x20)	//ignore control characters
                break;
            currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "%c", currentChar);
            break;
        }
    }

    if (openSpan) {
        currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "</span>");
    }

    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "</div>");

    delete[] tabBuffer;

    //add closing context
    currentBufferOffset += sprintf(clipbuffer + currentBufferOffset, "</body>\r\n</html>\r\n");
    endHTML = currentBufferOffset;

    QClipboard* clipboard = QApplication::clipboard();

    QMimeData* mimeData = new QMimeData();

    mimeData->setHtml(clipbuffer);
    mimeData->setText(textbuf);

    clipboard->setMimeData(mimeData, QClipboard::Clipboard);

    delete[] clipbuffer;
    delete[] textbuf;
}

void ExporterClass::fillScintillaData(QsciScintilla* scintillaEditor)
{ 
    int start = 0;
    int end = 0;
    bool doColourise = true;
    int len = 0;
    int tabSize = (int)scintillaEditor->SendScintilla(SCI_GETTABWIDTH); 
    int codePage = (int)scintillaEditor->SendScintilla(SCI_GETCODEPAGE);

    if (scintillaEditor->hasSelectedText())
    {
        start = (int)scintillaEditor->SendScintilla(SCI_GETSELECTIONSTART);
        end = (int)scintillaEditor->SendScintilla(SCI_GETSELECTIONEND);
        doColourise = false;
        len = end - start;
    }
    else
    {
        start = 0;
        len = scintillaEditor->length();
        end = len;
    }
    csd.tabSize = tabSize;
    csd.currentCodePage = codePage;
    csd.nrChars = len;
    csd.dataBuffer = new char[static_cast<size_t>(csd.nrChars) * 2 + 2];
    csd.styles = new StyleData[NRSTYLES];


    Sci_TextRange tr{};
    tr.chrg.cpMin = start;
    tr.chrg.cpMax = end;
    tr.lpstrText = csd.dataBuffer;

    if (doColourise)
        scintillaEditor->SendScintilla(SCI_COLOURISE, start, end);	//colourise doc so stylers are set
    scintillaEditor->SendScintilla(SCI_GETSTYLEDTEXT, 0, &tr);

    csd.nrStyleSwitches = 0, csd.nrUsedStyles = 1;	//Default always
    csd.totalFontStringLength = 0;
    int prevStyle = -1;
    int currentStyle = -1;
    for (int i = 0; i < NRSTYLES; i++) {
        csd.usedStyles[i] = false;
    }

    csd.usedStyles[STYLE_DEFAULT] = true;

    scintillaEditor->SendScintilla(SCI_STYLEGETFONT, STYLE_DEFAULT, (csd.styles[STYLE_DEFAULT].fontString));
    csd.totalFontStringLength += (int)strlen((csd.styles[STYLE_DEFAULT].fontString));
    csd.styles[STYLE_DEFAULT].size = (int)scintillaEditor->SendScintilla(SCI_STYLEGETSIZE, STYLE_DEFAULT);
    csd.styles[STYLE_DEFAULT].bold = (int)scintillaEditor->SendScintilla(SCI_STYLEGETBOLD, STYLE_DEFAULT);
    csd.styles[STYLE_DEFAULT].italic = (int)scintillaEditor->SendScintilla(SCI_STYLEGETITALIC, STYLE_DEFAULT);
    csd.styles[STYLE_DEFAULT].underlined = (int)scintillaEditor->SendScintilla(SCI_STYLEGETUNDERLINE, STYLE_DEFAULT);
    csd.styles[STYLE_DEFAULT].fgColor = (int)scintillaEditor->SendScintilla(SCI_STYLEGETFORE, STYLE_DEFAULT);
    csd.styles[STYLE_DEFAULT].bgColor = (int)scintillaEditor->SendScintilla(SCI_STYLEGETBACK, STYLE_DEFAULT);
    csd.styles[STYLE_DEFAULT].eolExtend = (bool)(scintillaEditor->SendScintilla(SCI_STYLEGETEOLFILLED, STYLE_DEFAULT) != 0);

    for (int i = 0; i < len; i++) {
        currentStyle = csd.dataBuffer[i * 2 + 1];
        if (currentStyle != prevStyle) {
            prevStyle = currentStyle;
            csd.nrStyleSwitches++;
        }
        if (currentStyle >= 0 && currentStyle < NRSTYLES && csd.usedStyles[currentStyle] == false) {
            csd.nrUsedStyles++;

            scintillaEditor->SendScintilla(SCI_STYLEGETFONT, currentStyle, (csd.styles[currentStyle].fontString));
            csd.totalFontStringLength += (int)strlen((csd.styles[currentStyle].fontString));
            csd.styles[currentStyle].size = (int)scintillaEditor->SendScintilla(SCI_STYLEGETSIZE, currentStyle);
            csd.styles[currentStyle].bold = (int)scintillaEditor->SendScintilla(SCI_STYLEGETBOLD, currentStyle);
            csd.styles[currentStyle].italic = (int)scintillaEditor->SendScintilla(SCI_STYLEGETITALIC, currentStyle);
            csd.styles[currentStyle].underlined = (int)scintillaEditor->SendScintilla(SCI_STYLEGETUNDERLINE, currentStyle);
            csd.styles[currentStyle].fgColor = (int)scintillaEditor->SendScintilla(SCI_STYLEGETFORE, currentStyle);
            csd.styles[currentStyle].bgColor = (int)scintillaEditor->SendScintilla(SCI_STYLEGETBACK, currentStyle);
            csd.styles[currentStyle].eolExtend = (bool)(scintillaEditor->SendScintilla(SCI_STYLEGETEOLFILLED, currentStyle) != 0);

            csd.usedStyles[currentStyle] = true;
        }
    }
    //QMessageBox::warning(NULL, "Warning", QString::number(csd.styles[STYLE_DEFAULT].size));
    //QMessageBox::warning(NULL, "Warning", QString::fromUtf8(csd.styles[STYLE_DEFAULT].fontString, stylesnlen));

}
